#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include "slab.h"
#include "mylog.h"

slab * slab_create()
{
	slab * p = (slab *)malloc(sizeof(struct slab));
	if(p == NULL){
		return NULL;
	}
	memset(p, 0, sizeof(struct slab));
	return p;
}

int slab_add(slab * p, unsigned int slot_size, unsigned char key)
{
	assert(slot_size > 0);
	if(key > SLAB_CLASS_MAX){
#ifndef NDEBUG
		logit(LV_ERROR, "slab_add: key %u is not accepted");
#endif
		return -1;
	}
	if(p->sc[key] != NULL){
#ifndef NDEBUG
		logit(LV_FATAL, "slab_add: key %u is occupied!!!");
#endif
		return -2;
	}
	p->sc[key] = scache_create(slot_size);
	if(p->sc[key] == NULL){
		return -3;
	}
	return 0;
}

static scache * scache_at(slab *p, unsigned int slot_size, unsigned char key)
{
	assert(p != NULL);
	if(p->sc[key] == NULL || p->sc[key]->slot_size != slot_size){
#ifndef NDEBUG
		logit(LV_ERROR, "scache at: no such scache at %u size %u", key, slot_size);
#endif
		return NULL;
	}
	return p->sc[key];
}

void * slab_alloc(slab *p, unsigned int size, unsigned char key)
{
	if(p == NULL || size <= 0 || key > SLAB_CLASS_MAX){
		return NULL;
	}
	scache * sc = scache_at(p, size, key);
	if(sc == NULL){
		return NULL;
	}
	return scache_alloc(sc);
}

int slab_destroy(slab *p)
{
	if(p == NULL){
		return -1;
	}
	scache ** scp = p->sc;
	while(*scp){
		if(scache_destroy(*scp) < 0){
			continue;
		}
		scp ++;
	}
	free(p);
	return 0;
}

int slab_clear(slab *p, unsigned int size, unsigned char key)
{
	if(p == NULL || size <= 0){
		return -1;
	}
	scache * sc = scache_at(p, size, key);
	if(sc == NULL){
		return -2;
	}
	return scache_clear(sc);
}

int slab_clear_all(slab *p)
{
	if(p == NULL){
		return -1;
	}
	scache ** scp = p->sc;
	while(*scp){
		if(scache_clear(*scp) < 0){
			return -2;
		}
		scp ++;
	}
	return 0;
}

#ifdef SLAB_MAIN
int main(int argc, char ** argv)
{
	logon();
	slab *p = slab_create();
	slab_add(p, sizeof(struct slab), 0);
	slab_add(p, sizeof(long long), 1);
	slab *s = NULL;
	long long *l = NULL;
	int i = 0;
	for(i=0; i<50; i++){
		s = slab_alloc(p, sizeof(struct slab), 0);
		l = slab_alloc(p, sizeof(long long), 1);
		printf("-- %p %p\n", s, l);
	}
	slab_clear_all(p);
	slab_destroy(p);
	logoff();
	return 0;
}
#endif
